package com.woniuxy.filters;

import com.woniu.entity.User;
import com.woniuxy.enums.TokenStatusEnum;
import com.woniuxy.jwt.JWTUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author WY
 * @Description: 用于过滤JWT，header中的token
 * @Package com.woniuxy.filters
 * @Date 2022/12/9 13:30
 * @Version 1.0
 */
@Component
public class JWTGlobalFilter implements GlobalFilter, Ordered {
    @Resource
    RedisTemplate redisTemplate;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //从请求头获取key为Authorization的值，就是我们的JWT：json web token；
        List<String> authorization = exchange.getRequest().getHeaders().get("Authorization");
        List<String> refreshTokenList = exchange.getRequest().getHeaders().get("RefreshToken");
        if (authorization != null && refreshTokenList !=null){
            String token = authorization.get(0);
            String refreshToken = refreshTokenList.get(0); //刷新token
            //校验token时候有效，如果有效果就放行
            TokenStatusEnum verify = JWTUtils.verify(token);
            //JWT校验没有过期，则直接放行
            if (verify.equals(TokenStatusEnum.TOKEN_SUCCESS)){
                return chain.filter(exchange);//放行
                //JWT过期了，但是refreshtoken还没有过期，重新生成token
            }else if(verify.equals(TokenStatusEnum.TOKEN_EXPIRE)){
            //说明没有token，判断 时候登录请求
                //如果JWT过期，但是时间未超过1个小时，refreshtoken还没有过期
                User user = (User) redisTemplate.opsForValue().get(refreshToken);
                //如果user取出后是null的，说明，ttl以及过期了
                if (user == null){
                    return Mono.error(new ArithmeticException("长时间未操作，请重新登录"));
                }else {
                    //30min到60分钟之间有操作
                    //如果refreshtoken还存在，则需要重新生成token
                    String newJWT = JWTUtils.generateToken(user.getUsername());
                    //把新生成的jwt通过响应头发送给前端
                    exchange.getResponse().getHeaders().set("token",newJWT);
                    //重新对refreshtoken进行计时
                    redisTemplate.expire(refreshToken,60, TimeUnit.MINUTES);
                    return chain.filter(exchange);//放行
                }
            }else {
                //如果token是bad，被篡改，则直接重新登录
                redisTemplate.delete(refreshToken);
                return Mono.error(new ArithmeticException("token被篡改，请重新登录"));
            }
        }else {//非业务请求，不用认证的请求
            //说明没有token，判断 时候登录请求
            if ("/auth/login".equals(exchange.getRequest().getPath().toString())) {
                return chain.filter(exchange);//放行
            }else {
                //判断该链接是否需要登录认证或者某个角色！
                //判断该链接是否需要登录认证或者某个角色！白名单！
            }
        }
        return chain.filter(exchange);//放行
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
